﻿using System;
using System.Collections.Generic;

namespace Hsenl {
    public abstract class SingleCombination : Combination { }

    public abstract class SingleCombination<T> : SingleCombination where T : Component {
        private T _member;

        protected sealed override int Form(IList<Component> components) {
            base.Form(components);
            if (components.Count != 1) Log.Warning($"combination components count has something the matter '{components.Count}'");
            var len = components.Count;
            if (len != 1) throw new Exception($"combination member mismatch: '{typeof(T)}'");
            for (var i = 0; i < len; i++) {
                switch (components[i]) {
                    case T t:
                        this._member = t;
                        break;
                    default:
                        throw new ArgumentOutOfRangeException($"'{this.GetType().Name}' '{components[i]?.GetType().Name}'");
                }
            }

            // UnityEngine.Debug.Log($"{this.GetType().Name}: {typeof(T)} - form - '{this._member}'");
            try {
                this.OnForm(this._member);
            }
            catch (Exception e) {
                Log.Error(e);
            }

            if (this.actionCounter != 0) {
                this.actionCounters[this.GetComponentCombineHashCode()] = this.actionCounter;
            }

            return this.GetComponentCombineHashCode();
        }

        protected sealed override int Break(IList<Component> components) {
            base.Break(components);
            if (components.Count != 1) Log.Warning($"combination components count has something the matter '{components.Count}'");
            for (int i = 0, len = components.Count; i < len; i++) {
                switch (components[i]) {
                    case T t:
                        this._member = t;
                        break;
                    default:
                        throw new ArgumentOutOfRangeException($"'{this.GetType().Name}' '{components[i]?.GetType().Name}'");
                }
            }

            // UnityEngine.Debug.Log($"{this.GetType().Name}: {typeof(T)} - break - '{this._member}'");
            try {
                this.OnBreak(this._member);
            }
            catch (Exception e) {
                Log.Error(e);
            }

            var hashcode = this.GetComponentCombineHashCode();
            if (this.actionCounters.TryGetValue(hashcode, out var counter)) {
                if (counter != this.actionCounter) {
                    // 调用过多少次EnqueueAction, 那么断开组合时, 就必须要DequeueAction多少次. 以保证每个回调都被正确的移除了
                    Log.Error($"decombin action counter error '{this.actionCounter}/{counter}' '{this.GetType().Name}'");
                }

                this.actionCounters.Remove(hashcode);
            }

            this.RemoveUserToken();
            this._member = null;

            return hashcode;
        }

        protected sealed override int GetComponentCombineHashCode() {
            return HashCode.Combine(this._member.InstanceId);
        }

        protected abstract void OnForm(T member);

        protected abstract void OnBreak(T member);
    }

    public abstract class SingleCombination<T1, T2> : SingleCombination where T1 : Component where T2 : Component {
        private T1 _member1;
        private T2 _member2;

        protected sealed override int Form(IList<Component> components) {
            base.Form(components);
            if (components.Count != 2) Log.Warning($"combination components count has something the matter '{components.Count}'");
            var len = components.Count;
            if (len != 2) throw new Exception($"combination member mismatch: '{typeof(T1)}' '{typeof(T2)}'");
            for (var i = 0; i < len; i++) {
                switch (components[i]) {
                    case T1 t1:
                        this._member1 = t1;
                        break;
                    case T2 t2:
                        this._member2 = t2;
                        break;
                    default:
                        throw new ArgumentOutOfRangeException($"'{this.GetType().Name}' '{components[i]?.GetType().Name}'");
                }
            }

            // UnityEngine.Debug.Log($"{this.GetType().Name}: {typeof(T1)} {typeof(T2)} - form - '{this._member1}' '{this._member2}'");
            try {
                this.OnForm(this._member1, this._member2);
            }
            catch (Exception e) {
                Log.Error(e);
            }

            if (this.actionCounter != 0) {
                this.actionCounters[this.GetComponentCombineHashCode()] = this.actionCounter;
            }

            return this.GetComponentCombineHashCode();
        }

        protected sealed override int Break(IList<Component> components) {
            base.Break(components);
            if (components.Count != 2) Log.Warning($"combination components count has something the matter '{components.Count}'");
            for (int i = 0, len = components.Count; i < len; i++) {
                switch (components[i]) {
                    case T1 t1:
                        this._member1 = t1;
                        break;
                    case T2 t2:
                        this._member2 = t2;
                        break;
                    default:
                        throw new ArgumentOutOfRangeException($"'{this.GetType().Name}' '{components[i]?.GetType().Name}'");
                }
            }

            // UnityEngine.Debug.Log($"{this.GetType().Name}: {typeof(T1)} {typeof(T2)} - break - '{this._member1}' '{this._member2}'");
            try {
                this.OnBreak(this._member1, this._member2);
            }
            catch (Exception e) {
                Log.Error(e);
            }

            var hashcode = this.GetComponentCombineHashCode();
            if (this.actionCounters.TryGetValue(hashcode, out var counter)) {
                if (counter != this.actionCounter) {
                    // 调用过多少次EnqueueAction, 那么断开组合时, 就必须要DequeueAction多少次. 以保证每个回调都被正确的移除了
                    Log.Error($"decombin action counter error '{this.actionCounter}/{counter}' '{this.GetType().Name}'");
                }

                this.actionCounters.Remove(hashcode);
            }

            this.RemoveUserToken();
            this._member1 = null;
            this._member2 = null;

            return hashcode;
        }

        protected sealed override int GetComponentCombineHashCode() {
            return HashCode.Combine(this._member1.InstanceId, this._member2.InstanceId);
        }

        protected abstract void OnForm(T1 member1, T2 member2);

        protected abstract void OnBreak(T1 member1, T2 member2);
    }

    public abstract class SingleCombination<T1, T2, T3> : SingleCombination where T1 : Component where T2 : Component where T3 : Component {
        private T1 _member1;
        private T2 _member2;
        private T3 _member3;

        protected sealed override int Form(IList<Component> components) {
            base.Form(components);
            if (components.Count != 3) Log.Warning($"combination components count has something the matter '{components.Count}'");
            for (int i = 0, len = components.Count; i < len; i++) {
                switch (components[i]) {
                    case T1 t1:
                        this._member1 = t1;
                        break;
                    case T2 t2:
                        this._member2 = t2;
                        break;
                    case T3 t3:
                        this._member3 = t3;
                        break;
                    default:
                        throw new ArgumentOutOfRangeException($"'{this.GetType().Name}' '{components[i]?.GetType().Name}'");
                }
            }

            // UnityEngine.Debug.Log($"{this.GetType().Name}: {typeof(T1)} {typeof(T2)} {typeof(T3)} - form - '{this._member1}' '{this._member2}' '{this._member3}'");
            try {
                this.OnForm(this._member1, this._member2, this._member3);
            }
            catch (Exception e) {
                Log.Error(e);
            }

            if (this.actionCounter != 0) {
                this.actionCounters[this.GetComponentCombineHashCode()] = this.actionCounter;
            }

            return this.GetComponentCombineHashCode();
        }

        protected sealed override int Break(IList<Component> components) {
            base.Break(components);
            if (components.Count != 3) Log.Warning($"combination components count has something the matter '{components.Count}'");
            for (int i = 0, len = components.Count; i < len; i++) {
                switch (components[i]) {
                    case T1 t1:
                        this._member1 = t1;
                        break;
                    case T2 t2:
                        this._member2 = t2;
                        break;
                    case T3 t3:
                        this._member3 = t3;
                        break;
                    default:
                        throw new ArgumentOutOfRangeException($"'{this.GetType().Name}' '{components[i]?.GetType().Name}'");
                }
            }

            // UnityEngine.Debug.Log(
            //     $"{this.GetType().Name}: {typeof(T1)} {typeof(T2)} {typeof(T3)} - break - '{this._member1}' '{this._member2}' '{this._member3}'");
            try {
                this.OnBreak(this._member1, this._member2, this._member3);
            }
            catch (Exception e) {
                Log.Error(e);
            }

            var hashcode = this.GetComponentCombineHashCode();
            if (this.actionCounters.TryGetValue(hashcode, out var counter)) {
                if (counter != this.actionCounter) {
                    // 调用过多少次EnqueueAction, 那么断开组合时, 就必须要DequeueAction多少次. 以保证每个回调都被正确的移除了
                    Log.Error($"decombin action counter error '{this.actionCounter}/{counter}' '{this.GetType().Name}'");
                }

                this.actionCounters.Remove(hashcode);
            }

            this.RemoveUserToken();
            this._member1 = null;
            this._member2 = null;
            this._member3 = null;

            return hashcode;
        }

        protected sealed override int GetComponentCombineHashCode() {
            return HashCode.Combine(this._member1.InstanceId, this._member2.InstanceId, this._member3.InstanceId);
        }

        protected abstract void OnForm(T1 member1, T2 member2, T3 member3);

        protected abstract void OnBreak(T1 member1, T2 member2, T3 member3);
    }

    public abstract class SingleCombination<T1, T2, T3, T4> : SingleCombination
        where T1 : Component where T2 : Component where T3 : Component where T4 : Component {
        private T1 _member1;
        private T2 _member2;
        private T3 _member3;
        private T4 _member4;

        protected sealed override int Form(IList<Component> components) {
            base.Form(components);
            if (components.Count != 4) Log.Warning($"combination components count has something the matter '{components.Count}'");
            for (int i = 0, len = components.Count; i < len; i++) {
                switch (components[i]) {
                    case T1 t1:
                        this._member1 = t1;
                        break;
                    case T2 t2:
                        this._member2 = t2;
                        break;
                    case T3 t3:
                        this._member3 = t3;
                        break;
                    case T4 t4:
                        this._member4 = t4;
                        break;
                    default:
                        throw new ArgumentOutOfRangeException($"'{this.GetType().Name}' '{components[i]?.GetType().Name}'");
                }
            }

            // UnityEngine.Debug.Log(
            //     $"{this.GetType().Name}: {typeof(T1)} {typeof(T2)} {typeof(T3)} {typeof(T4)} - form - '{this._member1}' '{this._member2}' '{this._member3}' '{this._member4}'");
            try {
                this.OnForm(this._member1, this._member2, this._member3, this._member4);
            }
            catch (Exception e) {
                Log.Error(e);
            }

            if (this.actionCounter != 0) {
                this.actionCounters[this.GetComponentCombineHashCode()] = this.actionCounter;
            }

            return this.GetComponentCombineHashCode();
        }

        protected sealed override int Break(IList<Component> components) {
            base.Break(components);
            if (components.Count != 4) Log.Warning($"combination components count has something the matter '{components.Count}'");
            for (int i = 0, len = components.Count; i < len; i++) {
                switch (components[i]) {
                    case T1 t1:
                        this._member1 = t1;
                        break;
                    case T2 t2:
                        this._member2 = t2;
                        break;
                    case T3 t3:
                        this._member3 = t3;
                        break;
                    case T4 t4:
                        this._member4 = t4;
                        break;
                    default:
                        throw new ArgumentOutOfRangeException($"'{this.GetType().Name}' '{components[i]?.GetType().Name}'");
                }
            }

            // UnityEngine.Debug.Log(
            //     $"{this.GetType().Name}: {typeof(T1)} {typeof(T2)} {typeof(T3)} {typeof(T4)} - break - '{this._member1}' '{this._member2}' '{this._member3}' '{this._member4}'");
            try {
                this.OnBreak(this._member1, this._member2, this._member3, this._member4);
            }
            catch (Exception e) {
                Log.Error(e);
            }

            var hashcode = this.GetComponentCombineHashCode();
            if (this.actionCounters.TryGetValue(hashcode, out var counter)) {
                if (counter != this.actionCounter) {
                    // 调用过多少次EnqueueAction, 那么断开组合时, 就必须要DequeueAction多少次. 以保证每个回调都被正确的移除了
                    Log.Error($"decombin action counter error '{this.actionCounter}/{counter}' '{this.GetType().Name}'");
                }

                this.actionCounters.Remove(hashcode);
            }

            this.RemoveUserToken();
            this._member1 = null;
            this._member2 = null;
            this._member3 = null;
            this._member4 = null;

            return hashcode;
        }

        protected sealed override int GetComponentCombineHashCode() {
            return HashCode.Combine(this._member1.InstanceId, this._member2.InstanceId, this._member3.InstanceId, this._member4.InstanceId);
        }

        protected abstract void OnForm(T1 member1, T2 member2, T3 member3, T4 member4);

        protected abstract void OnBreak(T1 member1, T2 member2, T3 member3, T4 member4);
    }

    public abstract class SingleCombination<T1, T2, T3, T4, T5> : SingleCombination
        where T1 : Component
        where T2 : Component
        where T3 : Component
        where T4 : Component
        where T5 : Component {
        private T1 _member1;
        private T2 _member2;
        private T3 _member3;
        private T4 _member4;
        private T5 _member5;

        protected sealed override int Form(IList<Component> components) {
            base.Form(components);
            if (components.Count != 5) Log.Warning($"combination components count has something the matter '{components.Count}'");
            for (int i = 0, len = components.Count; i < len; i++) {
                switch (components[i]) {
                    case T1 t1:
                        this._member1 = t1;
                        break;
                    case T2 t2:
                        this._member2 = t2;
                        break;
                    case T3 t3:
                        this._member3 = t3;
                        break;
                    case T4 t4:
                        this._member4 = t4;
                        break;
                    case T5 t5:
                        this._member5 = t5;
                        break;
                    default:
                        throw new ArgumentOutOfRangeException($"'{this.GetType().Name}' '{components[i]?.GetType().Name}'");
                }
            }

            // UnityEngine.Debug.Log(
            //     $"{this.GetType().Name}: {typeof(T1)} {typeof(T2)} {typeof(T3)} {typeof(T4)} {typeof(T5)}" +
            //     $"- form - '{this._member1}' '{this._member2}' '{this._member3}' '{this._member4}' '{this._member5}'");
            try {
                this.OnForm(this._member1, this._member2, this._member3, this._member4, this._member5);
            }
            catch (Exception e) {
                Log.Error(e);
            }

            if (this.actionCounter != 0) {
                this.actionCounters[this.GetComponentCombineHashCode()] = this.actionCounter;
            }

            return this.GetComponentCombineHashCode();
        }

        protected sealed override int Break(IList<Component> components) {
            base.Break(components);
            if (components.Count != 5) Log.Warning($"combination components count has something the matter '{components.Count}'");
            for (int i = 0, len = components.Count; i < len; i++) {
                switch (components[i]) {
                    case T1 t1:
                        this._member1 = t1;
                        break;
                    case T2 t2:
                        this._member2 = t2;
                        break;
                    case T3 t3:
                        this._member3 = t3;
                        break;
                    case T4 t4:
                        this._member4 = t4;
                        break;
                    case T5 t5:
                        this._member5 = t5;
                        break;
                    default:
                        throw new ArgumentOutOfRangeException($"'{this.GetType().Name}' '{components[i]?.GetType().Name}'");
                }
            }

            // UnityEngine.Debug.Log(
            //     $"{this.GetType().Name}: {typeof(T1)} {typeof(T2)} {typeof(T3)} {typeof(T4)} {typeof(T5)}" +
            //     $"- break - '{this._member1}' '{this._member2}' '{this._member3}' '{this._member4}' '{this._member5}'");
            try {
                this.OnBreak(this._member1, this._member2, this._member3, this._member4, this._member5);
            }
            catch (Exception e) {
                Log.Error(e);
            }

            var hashcode = this.GetComponentCombineHashCode();
            if (this.actionCounters.TryGetValue(hashcode, out var counter)) {
                if (counter != this.actionCounter) {
                    // 调用过多少次EnqueueAction, 那么断开组合时, 就必须要DequeueAction多少次. 以保证每个回调都被正确的移除了
                    Log.Error($"decombin action counter error '{this.actionCounter}/{counter}' '{this.GetType().Name}'");
                }

                this.actionCounters.Remove(hashcode);
            }

            this.RemoveUserToken();
            this._member1 = null;
            this._member2 = null;
            this._member3 = null;
            this._member4 = null;
            this._member5 = null;

            return hashcode;
        }

        protected sealed override int GetComponentCombineHashCode() {
            return HashCode.Combine(this._member1.InstanceId, this._member2.InstanceId, this._member3.InstanceId, this._member4.InstanceId,
                this._member5.InstanceId);
        }

        protected abstract void OnForm(T1 member1, T2 member2, T3 member3, T4 member4, T5 member5);

        protected abstract void OnBreak(T1 member1, T2 member2, T3 member3, T4 member4, T5 member5);
    }

    /// <summary>
    /// basicEntity: 复合组合, 都是从最低层开始, 所以, basicEntity 就是最低层实体. 假如是指定实体列表的话, 那就是[0]为 basicEntity
    /// entity: 当前进行判断的实体
    /// groupIndex: 当前是对哪个组进行判断
    /// </summary>
    public delegate CustomCompositeReturn CompositeCombinationCustomRule();

    public abstract class CompositeCombination : Combination {
        internal CompositeCombinationMode CompositeCombinationMode { get; set; }

        // 该回调只会在项目初始化的时候调用一次
        protected internal abstract Type[][] GetTypeGroups();

        // 该回调只会在项目初始化的时候调用一次
        protected internal virtual CompositeCombinationMode GetCombinationMode() {
            return CompositeCombinationMode.Normal;
        }

        // 该回调只会在项目初始化的时候调用一次
        protected sealed override Type[] GetOverrideCombinations() {
            return null;
        }

        // 该回调会在每次复合匹配的时候调用
        // basic: 起始实体, 对应的是groups[0]的第一组, 尝试形成组合时, 会首先判断第一组, 只有第一组判断成功了, 该函数才会被调用.
        // parent: 当前尝试形成组合的另一个实体, 因为复合组合总是从子级向上进行匹配的, 所以是parent
        //          同时, 因为是 ref, 所以我们可以指定一个父级以替换系统给我提供的父级, 匹配会从我们给的父级继续向上匹配
        // groupIndex: 当前进行匹配的是第几组. 因为第一组在系统内部会首先匹配, 所以, 我们使用该函数时, groupIndex总是从1开始的
        // layer: 当前父级相对于basic是第几层, 例如basic.Parent是第一层, basic.Parent.Parent是第二层
        public virtual CustomCompositeReturn GetCustomRule(Entity basic, ref Entity parent, int groupIndex, int layer) {
            return CustomCompositeReturn.NoHanle;
        }
    }

    public abstract class CompositeCombination<T1, T2> : CompositeCombination where T1 : Component where T2 : Component {
        private T1 _member1;
        private T2 _member2;

        protected sealed override int Form(IList<Component> components) {
            base.Form(components);
            if (components.Count != 2) Log.Warning($"combination components count has something the matter '{components.Count}'");
            var len = components.Count;
            if (len != 2) throw new Exception($"combination member mismatch: '{typeof(T1)}' '{typeof(T2)}'");
            for (var i = 0; i < len; i++) {
                switch (components[i]) {
                    case T1 t1:
                        this._member1 = t1;
                        break;
                    case T2 t2:
                        this._member2 = t2;
                        break;
                    default:
                        throw new ArgumentOutOfRangeException($"'{this.GetType().Name}' '{components[i]?.GetType().Name}'");
                }
            }

            // UnityEngine.Debug.Log($"{this.GetType().Name}: {typeof(T1)} {typeof(T2)} - form - '{this._member1}' '{this._member2}'");
            try {
                this.OnForm(this._member1, this._member2);
            }
            catch (Exception e) {
                Log.Error(e);
            }

            if (this.actionCounter != 0) {
                this.actionCounters[this.GetComponentCombineHashCode()] = this.actionCounter;
            }

            return this.GetComponentCombineHashCode();
        }

        protected sealed override int Break(IList<Component> components) {
            base.Break(components);
            if (components.Count != 2) Log.Warning($"combination components count has something the matter '{components.Count}'");
            for (int i = 0, len = components.Count; i < len; i++) {
                switch (components[i]) {
                    case T1 t1:
                        this._member1 = t1;
                        break;
                    case T2 t2:
                        this._member2 = t2;
                        break;
                    default:
                        throw new ArgumentOutOfRangeException($"'{this.GetType().Name}' '{components[i]?.GetType().Name}'");
                }
            }

            // UnityEngine.Debug.Log($"{this.GetType().Name}: {typeof(T1)} {typeof(T2)} - break - '{this._member1}' '{this._member2}'");
            try {
                this.OnBreak(this._member1, this._member2);
            }
            catch (Exception e) {
                Log.Error(e);
            }

            var hashcode = this.GetComponentCombineHashCode();
            if (this.actionCounters.TryGetValue(hashcode, out var counter)) {
                if (counter != this.actionCounter) {
                    // 调用过多少次EnqueueAction, 那么断开组合时, 就必须要DequeueAction多少次. 以保证每个回调都被正确的移除了
                    Log.Error($"decombin action counter error '{this.actionCounter}/{counter}' '{this.GetType().Name}'");
                }

                this.actionCounters.Remove(hashcode);
            }

            this.RemoveUserToken();
            this._member1 = null;
            this._member2 = null;

            return hashcode;
        }

        protected sealed override int GetComponentCombineHashCode() {
            return HashCode.Combine(this._member1.InstanceId, this._member2.InstanceId);
        }

        protected abstract void OnForm(T1 member1, T2 member2);

        protected abstract void OnBreak(T1 member1, T2 member2);

        protected internal override Type[][] GetTypeGroups() {
            return new[] {
                new[] { typeof(T1) },
                new[] { typeof(T2) },
            };
        }
    }

    public abstract class CompositeCombination<T1, T2, T3> : CompositeCombination where T1 : Component where T2 : Component where T3 : Component {
        private T1 _member1;
        private T2 _member2;
        private T3 _member3;

        protected sealed override int Form(IList<Component> components) {
            base.Form(components);
            if (components.Count != 3) Log.Warning($"combination components count has something the matter '{components.Count}'");
            for (int i = 0, len = components.Count; i < len; i++) {
                switch (components[i]) {
                    case T1 t1:
                        this._member1 = t1;
                        break;
                    case T2 t2:
                        this._member2 = t2;
                        break;
                    case T3 t3:
                        this._member3 = t3;
                        break;
                    default:
                        throw new ArgumentOutOfRangeException($"'{this.GetType().Name}' '{components[i]?.GetType().Name}'");
                }
            }

            // UnityEngine.Debug.Log($"{this.GetType().Name}: {typeof(T1)} {typeof(T2)} {typeof(T3)} - form - '{this._member1}' '{this._member2}' '{this._member3}'");
            try {
                this.OnForm(this._member1, this._member2, this._member3);
            }
            catch (Exception e) {
                Log.Error(e);
            }

            if (this.actionCounter != 0) {
                this.actionCounters[this.GetComponentCombineHashCode()] = this.actionCounter;
            }

            return this.GetComponentCombineHashCode();
        }

        protected sealed override int Break(IList<Component> components) {
            base.Break(components);
            if (components.Count != 3) Log.Warning($"combination components count has something the matter '{components.Count}'");
            for (int i = 0, len = components.Count; i < len; i++) {
                switch (components[i]) {
                    case T1 t1:
                        this._member1 = t1;
                        break;
                    case T2 t2:
                        this._member2 = t2;
                        break;
                    case T3 t3:
                        this._member3 = t3;
                        break;
                    default:
                        throw new ArgumentOutOfRangeException($"'{this.GetType().Name}' '{components[i]?.GetType().Name}'");
                }
            }

            // UnityEngine.Debug.Log(
            //     $"{this.GetType().Name}: {typeof(T1)} {typeof(T2)} {typeof(T3)} - break - '{this._member1}' '{this._member2}' '{this._member3}'");
            try {
                this.OnBreak(this._member1, this._member2, this._member3);
            }
            catch (Exception e) {
                Log.Error(e);
            }

            var hashcode = this.GetComponentCombineHashCode();
            if (this.actionCounters.TryGetValue(hashcode, out var counter)) {
                if (counter != this.actionCounter) {
                    // 调用过多少次EnqueueAction, 那么断开组合时, 就必须要DequeueAction多少次. 以保证每个回调都被正确的移除了
                    Log.Error($"decombin action counter error '{this.actionCounter}/{counter}' '{this.GetType().Name}'");
                }

                this.actionCounters.Remove(hashcode);
            }

            this.RemoveUserToken();
            this._member1 = null;
            this._member2 = null;
            this._member3 = null;

            return hashcode;
        }

        protected sealed override int GetComponentCombineHashCode() {
            return HashCode.Combine(this._member1.InstanceId, this._member2.InstanceId, this._member3.InstanceId);
        }

        protected abstract void OnForm(T1 member1, T2 member2, T3 member3);

        protected abstract void OnBreak(T1 member1, T2 member2, T3 member3);

        protected internal override Type[][] GetTypeGroups() {
            return new[] {
                new[] { typeof(T1), typeof(T2) },
                new[] { typeof(T3) },
            };
        }
    }

    public abstract class CompositeCombination<T1, T2, T3, T4> : CompositeCombination
        where T1 : Component where T2 : Component where T3 : Component where T4 : Component {
        private T1 _member1;
        private T2 _member2;
        private T3 _member3;
        private T4 _member4;

        protected sealed override int Form(IList<Component> components) {
            base.Form(components);
            if (components.Count != 4) Log.Warning($"combination components count has something the matter '{components.Count}'");
            for (int i = 0, len = components.Count; i < len; i++) {
                switch (components[i]) {
                    case T1 t1:
                        this._member1 = t1;
                        break;
                    case T2 t2:
                        this._member2 = t2;
                        break;
                    case T3 t3:
                        this._member3 = t3;
                        break;
                    case T4 t4:
                        this._member4 = t4;
                        break;
                    default:
                        throw new ArgumentOutOfRangeException($"'{this.GetType().Name}' '{components[i]?.GetType().Name}'");
                }
            }

            // UnityEngine.Debug.Log(
            //     $"{this.GetType().Name}: {typeof(T1)} {typeof(T2)} {typeof(T3)} {typeof(T4)} - form - '{this._member1}' '{this._member2}' '{this._member3}' '{this._member4}'");
            try {
                this.OnForm(this._member1, this._member2, this._member3, this._member4);
            }
            catch (Exception e) {
                Log.Error(e);
            }

            if (this.actionCounter != 0) {
                this.actionCounters[this.GetComponentCombineHashCode()] = this.actionCounter;
            }

            return this.GetComponentCombineHashCode();
        }

        protected sealed override int Break(IList<Component> components) {
            base.Break(components);
            if (components.Count != 4) Log.Warning($"combination components count has something the matter '{components.Count}'");
            for (int i = 0, len = components.Count; i < len; i++) {
                switch (components[i]) {
                    case T1 t1:
                        this._member1 = t1;
                        break;
                    case T2 t2:
                        this._member2 = t2;
                        break;
                    case T3 t3:
                        this._member3 = t3;
                        break;
                    case T4 t4:
                        this._member4 = t4;
                        break;
                    default:
                        throw new ArgumentOutOfRangeException($"'{this.GetType().Name}' '{components[i]?.GetType().Name}'");
                }
            }

            // UnityEngine.Debug.Log(
            //     $"{this.GetType().Name}: {typeof(T1)} {typeof(T2)} {typeof(T3)} {typeof(T4)} - break - '{this._member1}' '{this._member2}' '{this._member3}' '{this._member4}'");
            try {
                this.OnBreak(this._member1, this._member2, this._member3, this._member4);
            }
            catch (Exception e) {
                Log.Error(e);
            }

            var hashcode = this.GetComponentCombineHashCode();
            if (this.actionCounters.TryGetValue(hashcode, out var counter)) {
                if (counter != this.actionCounter) {
                    // 调用过多少次EnqueueAction, 那么断开组合时, 就必须要DequeueAction多少次. 以保证每个回调都被正确的移除了
                    Log.Error($"decombin action counter error '{this.actionCounter}/{counter}' '{this.GetType().Name}'");
                }

                this.actionCounters.Remove(hashcode);
            }

            this.RemoveUserToken();
            this._member1 = null;
            this._member2 = null;
            this._member3 = null;
            this._member4 = null;

            return hashcode;
        }

        protected sealed override int GetComponentCombineHashCode() {
            return HashCode.Combine(this._member1.InstanceId, this._member2.InstanceId, this._member3.InstanceId, this._member4.InstanceId);
        }

        protected abstract void OnForm(T1 member1, T2 member2, T3 member3, T4 member4);

        protected abstract void OnBreak(T1 member1, T2 member2, T3 member3, T4 member4);

        protected internal override Type[][] GetTypeGroups() {
            return new[] {
                new[] { typeof(T1), typeof(T2), typeof(T3) },
                new[] { typeof(T4) },
            };
        }
    }

    public abstract class CompositeCombination<T1, T2, T3, T4, T5> : CompositeCombination
        where T1 : Component
        where T2 : Component
        where T3 : Component
        where T4 : Component
        where T5 : Component {
        private T1 _member1;
        private T2 _member2;
        private T3 _member3;
        private T4 _member4;
        private T5 _member5;

        protected sealed override int Form(IList<Component> components) {
            base.Form(components);
            if (components.Count != 5) Log.Warning($"combination components count has something the matter '{components.Count}'");
            for (int i = 0, len = components.Count; i < len; i++) {
                switch (components[i]) {
                    case T1 t1:
                        this._member1 = t1;
                        break;
                    case T2 t2:
                        this._member2 = t2;
                        break;
                    case T3 t3:
                        this._member3 = t3;
                        break;
                    case T4 t4:
                        this._member4 = t4;
                        break;
                    case T5 t5:
                        this._member5 = t5;
                        break;
                    default:
                        throw new ArgumentOutOfRangeException($"'{this.GetType().Name}' '{components[i]?.GetType().Name}'");
                }
            }

            // UnityEngine.Debug.Log(
            //     $"{this.GetType().Name}: {typeof(T1)} {typeof(T2)} {typeof(T3)} {typeof(T4)} {typeof(T5)}" +
            //     $"- form - '{this._member1}' '{this._member2}' '{this._member3}' '{this._member4}' '{this._member5}'");
            try {
                this.OnForm(this._member1, this._member2, this._member3, this._member4, this._member5);
            }
            catch (Exception e) {
                Log.Error(e);
            }

            if (this.actionCounter != 0) {
                this.actionCounters[this.GetComponentCombineHashCode()] = this.actionCounter;
            }

            return this.GetComponentCombineHashCode();
        }

        protected sealed override int Break(IList<Component> components) {
            base.Break(components);
            if (components.Count != 5) Log.Warning($"combination components count has something the matter '{components.Count}'");
            for (int i = 0, len = components.Count; i < len; i++) {
                switch (components[i]) {
                    case T1 t1:
                        this._member1 = t1;
                        break;
                    case T2 t2:
                        this._member2 = t2;
                        break;
                    case T3 t3:
                        this._member3 = t3;
                        break;
                    case T4 t4:
                        this._member4 = t4;
                        break;
                    case T5 t5:
                        this._member5 = t5;
                        break;
                    default:
                        throw new ArgumentOutOfRangeException($"'{this.GetType().Name}' '{components[i]?.GetType().Name}'");
                }
            }

            // UnityEngine.Debug.Log(
            //     $"{this.GetType().Name}: {typeof(T1)} {typeof(T2)} {typeof(T3)} {typeof(T4)} {typeof(T5)}" +
            //     $"- break - '{this._member1}' '{this._member2}' '{this._member3}' '{this._member4}' '{this._member5}'");
            try {
                this.OnBreak(this._member1, this._member2, this._member3, this._member4, this._member5);
            }
            catch (Exception e) {
                Log.Error(e);
            }

            var hashcode = this.GetComponentCombineHashCode();
            if (this.actionCounters.TryGetValue(hashcode, out var counter)) {
                if (counter != this.actionCounter) {
                    // 调用过多少次EnqueueAction, 那么断开组合时, 就必须要DequeueAction多少次. 以保证每个回调都被正确的移除了
                    Log.Error($"decombin action counter error '{this.actionCounter}/{counter}' '{this.GetType().Name}'");
                }

                this.actionCounters.Remove(hashcode);
            }

            this.RemoveUserToken();
            this._member1 = null;
            this._member2 = null;
            this._member3 = null;
            this._member4 = null;
            this._member5 = null;

            return hashcode;
        }

        protected sealed override int GetComponentCombineHashCode() {
            return HashCode.Combine(this._member1.InstanceId, this._member2.InstanceId, this._member3.InstanceId, this._member4.InstanceId,
                this._member5.InstanceId);
        }

        protected abstract void OnForm(T1 member1, T2 member2, T3 member3, T4 member4, T5 member5);

        protected abstract void OnBreak(T1 member1, T2 member2, T3 member3, T4 member4, T5 member5);

        protected internal override Type[][] GetTypeGroups() {
            return new[] {
                new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4) },
                new[] { typeof(T5) },
            };
        }
    }
}